#include "LineDrawer.h"
#include "Engine.h"
#include "GameState.h"
#include "Camera.h"

IDirect3DVertexDeclaration9* DebugVert::s_dcl = 0;

void DebugVert::RegisterDeclarations()
{
    D3DVERTEXELEMENT9 VertexElements[] =
    {
        {
            0,0,D3DDECLTYPE_FLOAT4, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION,0
        },
        {
            0, 16, D3DDECLTYPE_FLOAT4, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TEXCOORD,0
        },
        D3DDECL_END()   
    };
    Engine::Instance()->GetDevice()->CreateVertexDeclaration(VertexElements, &DebugVert::s_dcl );
}
void LineDrawer::Initialize()
{
    //register the static declaration for this type of vertex 
    DebugVert::RegisterDeclarations();

    //a line has two vertices
    int vertexCount = 2;
    //create a vertex buffer on the GPU
    Engine::Instance()->GetDevice()->CreateVertexBuffer( vertexCount * sizeof(DebugVert),
        D3DUSAGE_DYNAMIC, 0,
        D3DPOOL_DEFAULT , &m_points, NULL ); 
}


void LineDrawer::drawLine(const btVector3& from,const btVector3& to,const btVector3& color)
{
    m_tFroms.push_back(D3DXVECTOR3(from.x(),from.y(),from.z()));
    m_tTos.push_back(D3DXVECTOR3(to.x(),to.y(),to.z()));
    m_tColors.push_back(D3DXVECTOR3(color.x(),color.y(),color.z()));
}
void LineDrawer::drawLine( const Vec3& from,const Vec3& to,const Vec3& color)
{
    m_tFroms.push_back(D3DXVECTOR3(from.m_x, from.m_y, from.m_z));
    m_tTos.push_back(D3DXVECTOR3(to.m_x, to.m_y, to.m_z));
    m_tColors.push_back(D3DXVECTOR3(color.m_x,color.m_y,color.m_z));
}
void LineDrawer::drawLine( const D3DXVECTOR3& from, const D3DXVECTOR3& to, const D3DXVECTOR3& color )
{
    m_tFroms.push_back(from);
    m_tTos.push_back(to);
    m_tColors.push_back(color);
}
void LineDrawer::drawLine( float fromX,float fromY,float fromZ, float toX,float toY,float toZ, float colR,float colG,float colB )
{
    m_tFroms.push_back(D3DXVECTOR3(fromX,fromY,fromZ));
    m_tTos.push_back(D3DXVECTOR3(toX, toY, toZ));
    m_tColors.push_back(D3DXVECTOR3(colR,colG,colB));
}
void LineDrawer::DrawAllLines()
{
    for(unsigned int i = 0; i < m_tFroms.size(); ++i)
    {
        VOID* pVertices;

        int BufferSize = sizeof( DebugVert ) * 2;

        DebugVert* cpuBuffer = new DebugVert[2];
        cpuBuffer[0].Set(m_tFroms[i].x,m_tFroms[i].y,m_tFroms[i].z, m_tColors[i].x,m_tColors[i].y,m_tColors[i].z);
        cpuBuffer[1].Set(m_tTos[i].x,m_tTos[i].y,m_tTos[i].z, m_tColors[i].x,m_tColors[i].y,m_tColors[i].z);

        TEST(m_points->Lock( 0, BufferSize, ( void** )&pVertices, D3DLOCK_DISCARD )); 

        memcpy( pVertices, cpuBuffer, BufferSize );

        TEST(m_points->Unlock());

        delete[] cpuBuffer;

        unsigned int cPasses;

        TEST(Engine::Instance()->GetDevice()->SetVertexDeclaration(DebugVert::s_dcl));
        TEST(Engine::Instance()->GetDevice()->SetStreamSource( 0, m_points, 0, sizeof( DebugVert ) ));
        ID3DXEffect* effect =  Engine::Instance()->GetCurrentState()->GetEffect(); 
        TEST(effect->SetTechnique("Debug"));
        D3DXMATRIXA16 identity;
        D3DXMatrixIdentity(&identity);
        TEST( effect->SetMatrix( "g_mWorld", &identity ) );
        identity *= Engine::Instance()->GetCurrentState()->GetCamera()->GetViewMatrix();
        TEST( effect->SetMatrix( "g_mView", &identity ) );
        identity = Engine::Instance()->GetCurrentState()->GetCamera()->GetProjectionMatrix();
        TEST( effect->SetMatrix( "g_mProj", &identity ) );
        TEST(effect->Begin(&cPasses, 0 ));
        for(unsigned int  iPass = 0; iPass < cPasses; iPass++ )
        {
            TEST(effect->BeginPass( iPass ));

            TEST(Engine::Instance()->GetDevice()->DrawPrimitive( D3DPT_LINELIST, 0, 1 ));

            TEST(effect->EndPass());
        }
        TEST(effect->End());
    }
}

void LineDrawer::Release()
{
    m_points->Release();
    DebugVert::s_dcl->Release();
}

void LineDrawer::reportErrorWarning(const char* warningString)
{
    std::string extras(warningString);
    Engine::Instance()->Error(TOSTRING(__LINE__), TOSTRING(__FILE__), &extras);
}